/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file logging.c 
 * pyhp logging support
 */

#include "logging.h"

#include <apr_strings.h>
#include <apr_xml.h>

#include <http_log.h>

/**
 * Writes a formatted logging message of the desidered logging type
 */
void pyhp_logf(request_rec *r, PyHPLogType type, char *fmt, ...)
{
    va_list ap;
    char *txt;

    va_start(ap, fmt);
    txt = apr_pvsprintf(r->pool, fmt, ap);
    pyhp_log(r, type, txt);
    va_end(ap);

    return;
}

/**
 * Writes a simple text message of the desidered logging type
 */
void pyhp_log(request_rec *r, PyHPLogType type, char *txt)
{
    PyHPLogLocation loc = pyhp_config_loglocation(r);
    PyHPLogType log_level = pyhp_config_loglevel(r);

    if (type < log_level)
        return;

    if ( (!r) )
        return;

    if ((r->connection->aborted)) {
        txt = apr_psprintf(r->pool, "[PyHP] Message: %s", txt);
        ap_log_error(APLOG_MARK, APLOG_ALERT, 0, r->server, "%s", txt);
    }
    else if (loc == PyHPLog_Apache) {
        txt = apr_psprintf(r->pool, "[PyHP] Message: %s", txt);
        ap_log_rerror(APLOG_MARK, APLOG_ALERT, 0, r, "%s", txt);
    }
    else if (loc == PyHPLog_Web) {
        apr_pool_t *p = r->pool;
        char *cur, *state;
        char *res = "";

        txt = apr_pstrdup(r->pool, txt);
        txt = (char*)apr_xml_quote_string(p, txt, 1);

        cur = apr_strtok(txt, "\t ", &state);
        while ( cur ) {
            char *sub = "&nbsp;";
            if ( *cur == '\t')
                sub = "&nbsp;&nbsp;&nbsp;&nbsp;";

            res  = apr_pstrcat(p, res, sub, txt, NULL);
            cur = apr_strtok(NULL, "\t ", &state);
            txt = cur;
        }
        res = apr_pstrcat(p, res, txt, NULL);

        txt = apr_psprintf(p, "<div style=\"background-color: #ffcccc; color: black; padding: 8px; margin: 0px; padding:0px;\">%s</div>", res);

        ap_rputs(txt, r);
    }
}

/**
 * stderr replacement for Python layer. Error message from python
 * will be written here. This function sends them to the pyhp_log
 */
static PyObject *pyhp_log_write(PyObject * self, PyObject * args)
{
    PyObject *text = NULL;
    
    if (!PyArg_ParseTuple(args, "O", &text))
    	return NULL;

    PyObject *req  = PyDict_GetItemString(self, "apache_request");
    request_rec *r = PyCObject_AsVoidPtr(req);

    PyObject *pool = PyDict_GetItemString(self, "apache_pool");
    apr_pool_t *p = PyCObject_AsVoidPtr(pool);

    char *txt = PyString_AsString(text);

    pyhp_log(r, PyHP_ERR, txt);

    Py_INCREF (Py_None);
    return Py_None;
}

/**
 * Logging functionality accessor for the python layer, will be
 * exposed as pyhp.log.log
 */
static PyObject *pyhp_log_log(PyObject *self, PyObject *args)
{
    PyObject *text = NULL;
    PyObject *level = NULL;
    
    if (!PyArg_ParseTuple(args, "OO", &level, &text))
    	return NULL;

    PyObject *req = PyDict_GetItemString(self, "apache_request");
    request_rec *r = PyCObject_AsVoidPtr(req);

    PyObject *pool = PyDict_GetItemString(self, "apache_pool");
    apr_pool_t *p = PyCObject_AsVoidPtr(pool);

    char *txt = PyString_AsString(text);
    long lvl = PyInt_AsLong(level);

    pyhp_log(r, lvl, txt);

    Py_INCREF(Py_None);
    return Py_None;
}

/**
 * Python layer accessor to change the logging level
 */
static PyObject *pyhp_log_set_level(PyObject *self, PyObject *args)
{
    pyhp_config *cfg;
    PyObject *level = NULL;
    
    if (!PyArg_ParseTuple(args, "O", &level))
    	return NULL;

    PyObject *req = PyDict_GetItemString(self, "apache_request");
    request_rec *r = PyCObject_AsVoidPtr(req);

    PyObject *pool = PyDict_GetItemString(self, "apache_pool");
    apr_pool_t *p = PyCObject_AsVoidPtr(pool);

    long lvl = PyInt_AsLong(level);
    cfg = pyhp_get_config(r);
    cfg->log_level = lvl;

    Py_INCREF(Py_None);
    return Py_None;
}

/**
 * Python layer accessor to change the logging type
 */
static PyObject *pyhp_log_set(PyObject *self, PyObject *args)
{
    pyhp_config *cfg;
    PyObject *text = NULL;
    
    if (!PyArg_ParseTuple(args, "O", &text))
    	return NULL;

    PyObject *req  = PyDict_GetItemString(self, "apache_request");
    request_rec *r = PyCObject_AsVoidPtr(req);

    PyObject *pool = PyDict_GetItemString(self, "apache_pool");
    apr_pool_t *p = PyCObject_AsVoidPtr(pool);

    char *txt = PyString_AsString(text);
    cfg = pyhp_get_config(r);
    cfg->log = apr_pstrdup(r->pool, txt);

    Py_INCREF(Py_None);
    return Py_None;
}

static PyMethodDef logging_method_table[] = {
    { "write", (PyCFunction)pyhp_log_write, METH_VARARGS,
                                    "Write data to PyHP Logging as an error" },
    { "log", (PyCFunction)pyhp_log_log, METH_VARARGS,
                   "Write data to PyHP Logging with the requested log level" },
    { "set_level", (PyCFunction)pyhp_log_set_level, METH_VARARGS,
                                             "Sets the current logging level"},
    { "set", (PyCFunction)pyhp_log_set, METH_VARARGS,
                                            "Sets the current logging output"},
    { NULL, NULL }
};

/**
 * Exports the logging constants and methods to the python layer
 * @see pyhp_layer_init
 */
void pyhp_logging_export(PyObject *dict, PyObject *self)
{
    PyObject *log = Py_InitModule4("pyhp_log", logging_method_table, "", self,
                                   PYTHON_API_VERSION);
    PyDict_SetItemString(dict, "log", log);
    Py_XDECREF(log);

    dict = PyModule_GetDict(log);
    PyDict_SetItemString(dict, "__internals", self);
    Py_XDECREF(self);

    self = PyInt_FromLong(PyHP_ERR);
    PyDict_SetItemString(dict, "ERR", self);
    Py_XDECREF(self);

    self = PyInt_FromLong(PyHP_WARN);
    PyDict_SetItemString(dict, "WARN", self);
    Py_XDECREF(self);

    self = PyInt_FromLong(PyHP_INFO);
    PyDict_SetItemString(dict, "INFO", self);
    Py_XDECREF(self);

    self = PyInt_FromLong(PyHP_DEBUG);
    PyDict_SetItemString(dict, "DEBUG", self);
    Py_XDECREF(self);
}

